/**
 * @class   wosh::ObjectFactory
 * @brief   CoreModule provides methods and managements of dynamic type recognition and allocation,
 *          supports and masquerades access to installed wosh::ObjectAllocators.
 *
 *
 *
 * \image html diagrams/ObjectFactory.png "wosh::ObjectFactory UML diagram"
 *
 *
 * Manager allocators:
 *  - Static allocator (built-in)
 *  - Dynamic allocator (as dll plugins)
 *
 *  - Remote allocators ( build a wrapper to a remote object, =location transparency)
 *
 * Rules:
 *  - Objects are destroyed by the allocator which instantiated it
 *
 * Allocation by:
 *  - classname
 *  - interface [version]
 *
 *
 *
 *
 * @ingroup CoreModules
 ****************************************************************************
 * @version 0.8.499 $Id: ObjectFactory.h 2831 2010-08-02 22:15:14Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_core
 * \htmlonly <hr/> \endhtmlonly
 * \section page_core_objectfactory Object Factory
 *
 * \note ObjectFactory and the current \c Object-Allocation model has been introduced in WOSH 0.8.013 [icarus]
 *
 * WOSH Framework is deeply based on polymorphism (inheritance and multiple-inheritance,
 * sometimes even diamond inheritance) and composition of classes. Moreover,
 * services are usually recognized by interfaces (abstract classes) they implement.
 * 
 * The current Interface/Broker model is still weak (not strongly typed), but
 * implementations are quite standardized and already \c explicitly implement
 * the reference interface (abstract class). For example, wosh::devices::ModemDsl
 * implements wosh::interfaces::devices::ModemDsl.
 *
 * There are some more points which make things complex:
 *  - Allocation from dynamic libraries (such as DLLs)
 *  - Support more implementation of same interface
 *  - Support more versions of same interface/implementation
 *  - Multiple (nested) inheritance, diamond inheritance
 *
 * Before explaning how the WOSH model works, here are the results:
 *  - simple, integrated MACROS for registering a new type
 *  - lookup and reverse lookup, nested, optional version and \c allocable patterns
 *  - methods for (de)allocation of objects, forwarded to the nearest/original allocator (scope)
 *  - tree-dump of the registered types (from child-to-parent and parent-to-child)
 *
 * Here is a sample of a rendered tree from \ref page_applications_woshshop "WOSH WorkShop front-end":
 * \image html extras/screenshots/WOSH.GUI.FormObjectFactory.2a.png "wosh::gui::FormObjectFactory::Tab 2a"
 *
 *
 * As you may have seen in the screenshot, the \c parent is not necessarly the
 * parent node. This is part of the multiple-inheritance support:
 * each type has only one defined parent (or none), which usually is the most
 * significative interface, but may have an unlimited number of other (direct) parent
 * and super-parent (nested).
 *
 * Let's start from the beginning: registration and maintenance of types.
 *
 * wosh::ObjectFactory is a skeleton for accessing to available (registered) \c Allocators
 * and providing standard function (as other wosh::WoshModule). Basically the component
 * forwards (iterative) common calls (such as create-new, search, ..) to registered allocators.
 *
 * wosh::ObjectAllocator is an particular Object capable of (de)allocating a set of object-types.
 * Once an allocator is unregistered, its services aren't available anymore, this is useful
 * when dealing with dynamic libraries/registration.
 *
 * \note support of dynamic plugin is planned but not integrated yet.
 *
 *
 * \todo explain Meyer singleton and initialization order (fiasco)
 *
 *
 * \code
WOSH_REGISTER_INTERFACE(wosh::network::SocketTcp, "", 1.00, _static_SocketTcp )
 * \endcode
 *
 * Someway, in another source files, dynamically executed before or after previous snipped,
 * the implementation is defined:
 * \code
WOSH_REGISTER(wosh::network::qt::SocketTcpQt, "wosh::network::SocketTcp", 1.0, _static_SocketTcpQt )
 * \endcode
 *
 *
 * Dynamic allocation-by-interface Snippet (from wosh::network::NetworkChannelTcp::initializingThread()):
 * \code
this->tcpSocket = ObjectFactory::createTypeOf<wosh::network::SocketTcp>();
if ( this->tcpSocket == NULL ) {
	Log(LOG_CRITICAL, ":initializingThread() FAILED Creating SocketTcp!" );
	return false;
 }
this->tcpSocket->setListener(this);
 * \endcode
 * 
 * It's so simple as amazing, until run-time we have no idea if there is really
 * an implementation of \c SocketTcp neither which it will be created. Indeed
 * this is a design choice and the template function is provided for convenience.
 *
 * It is possible to define the class-type using:
 * \code
IReflection* new_obj = ObjectFactory::createTypeOf( "wosh::network::Qt::SocketTcpQt" );
wosh::network::Qt::SocketTcpQt* new_socket = dynamic_cast<wosh::network::Qt::SocketTcpQt>(new_obj);
new_socket->setListener(this);
 * \endcode
 *
 * Object should be destroyed as follow:
 * \code
WRESULT destroyed = ObjectFactory::destroy(this->tcpSocket);
 * \endcode
 *
 *
 *
 * @todo [..]
 *
 *
 * \see wosh::ObjectFactory
 * \see wosh::ObjectAllocator
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ThreadS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_ObjectFactory_H__
 #define __WOSH_Core_ObjectFactory_H__

 #include <woshDefs.h>
 #include <core/WoshModule.h>
 #include <core/Containers.h>
 #include <core/ObjectAllocator.h>


namespace wosh {

 #define _ObjectFactory_NAME					"ObjectFactory"
 #define _ObjectFactory_URI						":Factory"

 #define _ObjectFactory_KEY_Count				"Count"

 #define _ObjectFactory_METHOD_remove_allocator	"remove_allocator"
 #define _SystemMonitor_METHOD_types_tree		"types_tree"
 #define _SystemMonitor_METHOD_supports_type	"supports_type"
 #define _SystemMonitor_METHOD_find_allocator	"find_allocator"

class WoshKernel;

class ObjectFactory : public WoshModule
 {
	WOSH_MODULE(wosh::ObjectFactory)

	protected:
		/**
		 * @brief  Default constructor. Call base constructor and initialize some properties and hosted methods.
		 * @param parent [in] WoshKernel singleton, passed to WoshModule constructor
		 * @note   Called by WoshKernel or by static getter (meyer singleton)
		 */
		ObjectFactory( const WoshKernel* parent = NULL );

		/**
		 * @brief  Call base class implementation and fix URI of allocators.
		 * @return result of WoshModule::onKernelInitializing()
		 */
		WRESULT onKernelInitializing();

		friend class wosh::WoshKernel;

	public:
		/**
		 * @brief  Destructor. Does nothing.
		 */
		virtual ~ObjectFactory();


/** @name Object Allocation - public methods
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Create a on object of an explicit type. Provided for convenience.
		 *         This form is preferred since compiler will validate types.
		 *         Example: createTypeOf<wosh::network::SocketTcp>()
		 * @return NULL if object can't be allocated; the new instance else, ownership is acquired by caller
		 * @see    ObjectFactory::createTypeOf()
		 */
		template <class OBJECT_TYPE>
		static OBJECT_TYPE* createTypeOf( bool strict = true ) {
			return dynamic_cast<OBJECT_TYPE*>(createTypeOf(OBJECT_TYPE::className(), 0.0, strict));
		 }
		/**
		 * @brief  Create a on object of an argument class-type and up-cast it to selected class. Provided for convenience.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface,
		 *         in this case it will search for nearest/updated implementation of the interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return NULL if object can't be allocated; the new instance else, ownership is acquired by caller
		 * @see    ObjectFactory::createTypeOf()
		 * @note   dynamic cast will return NULL on casting errors; note that in there case, memory will be lost
		 */
		template <class DYNAMIC_CAST>
		static DYNAMIC_CAST* createTypeOf( const std::string& className, double version_pattern = 0.0, bool strict = false ) {
			return dynamic_cast<DYNAMIC_CAST*>(createTypeOf(className, version_pattern, strict));
		 }

		/**
		 * @brief  Find first Allocator which matches (supports) the query and forward call createTypeOf(). Reentrant.
		 *         Object is registered in the allocators list, so it may be destroyed later within same scope.
		 *         Search is iterative.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface,
		 *         in this case it will search for nearest/updated implementation of the interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return NULL if object can't be allocated; the new instance else, ownership is acquired by caller
		 * @see    ObjectFactory::findAllocatorOf_()
		 * @see    ObjectAllocator::createTypeOf()
		 * @see    ObjectFactory::destroy()
		 */
		static IReflection* createTypeOf( const std::string& className, double version_pattern = 0.0, bool strict = false );
		/**
		 * @brief  Forward call to owner-allocator to destroy the instance. Reentrant.
		 *         This is a sort of 'delete object' but it is scoped within the original allocator.
		 *         It is convenient and save especially when using plugins and DLLs.
		 * @param  object [in] object to be destryoed (downcasted to IReflection interface)
		 * @return WRET_ERR_PARAM if argument is NULL or its owner-allocator was not found; WRET_OK else (on succeded deletion)
		 * @see    ObjectFactory::findAllocatorOf_()
		 * @see    ObjectAllocator::createTypeOf()
		 * @see    ObjectAllocator::destroy()
		 * @note   Object must have been allocated through createTypeOf() call (directly on indirecttly)
		 */
		static WRESULT destroy( IReflection* object );

		/**
		 * @brief  Find first Allocator which matches (supports) the query. Reentrant.
		 *         Only allocable classes are evaluated.
		 *         Search is iterative.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface,
		 *         in this case it will search for nearest/updated implementation of the interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return true if there is at least one allocator able to create the object; false else
		 * @see    ObjectAllocator::isSupported()
		 */
		static bool isAllocable( const std::string& className, double version_pattern = 0.0 );
		/**
		 * @brief  Retrieve information about a specific class (type). 
		 * @param  class_list [out] output list of class-type information. first item is the object itself, second item is
		 *         usually the nearest parent, following items are gran-parents.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return WRET_ERR_PARAM if argument classname(version) was not found; WRET_OK else
		 * @see    ObjectFactory::findAllocatorOf_()
		 * @see    ObjectAllocator::gatherInfoOf()
		 */
		static WRESULT gatherInfoOf( std::vector<ObjectTypeInfo>& class_list, const std::string& className, double version_pattern = 0.0 );

		/**
		 * @brief  Retrieve information about a implementations of a specific class (type). 
		 * @param  class_list [out] output list of class-type information. first item may be the object itself, following
		 *         items are the children collection, built recursevely.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @param  allocable [in] when true, it will filter abstract children (only allocable class will be included)
		 * @return WRET_ERR_PARAM if argument classname(version) not found; WRET_OK else
		 * @see    ObjectAllocator::findChildsOf()
		 */
		static WRESULT findChildsOf( std::vector<ObjectTypeInfo>& class_list, const std::string& className, double version_pattern = 0.0, bool allocable = true );

//@}
/** @name Allocators - public methods
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Find first Allocator which matches (supports) the query. Reentrant.
		 * @param  allocator [out] on success, result of the search is stored in this output parameter
		 * @param  className [in] full class name of the object (including namespace), may be an abstract interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @param  allocable [in] when true, it will filter results for non-abstract object only
		 * @return WRET_ERR_PARAM if the object (query) is not supported by any allocator; WRET_OK else
		 * @see    ObjectAllocator::isSupported()
		 */
		static WRESULT findAllocatorOf( std::string& allocator, const std::string& className, double version_pattern = 0.0, bool allocable = true );
		/**
		 * @brief  Register an Allocator. Reentrant.
		 * @param  allocator [in] ObjectAllocator to be added to the list
		 * @return WRET_ERR_PARAM if parameter is NULL or not found; WRET_OK else
		 */
		WRESULT installAllocator( ObjectAllocator* allocator );
		/**
		 * @brief  UnRegister an Allocator. Reentrant. Instance is not destroyed.
		 * @param  allocator [in] ObjectAllocator to be removed from the list
		 * @return WRET_ERR_PARAM if parameter is NULL or not found; WRET_OK else
		 */
		WRESULT removeAllocator( ObjectAllocator* allocator );

//@}
/** @name Internal Mehods and Allocators management
 * @{
 ******************************************************************************/
	private:
		/**
		 * @brief  Access the ObjectFactory singleton. Meyer Pattern.
		 *         Static reference is allocated on first use, destroyed by WoshKernel
		 * @return reference to ObjectFactory singleton
		 * @note   this is designed using meyer singleton because some allocators may be allocated
		 *         very early (such as StaticAllocator), so basically the kernel will acquire
		 *         (on-creation) the object, and will destroy it in destructor.
		 *         (later, compiler will destroy only the static pointer)
		 */
		static ObjectFactory& getInstance();

	private:
		/**
		 * @brief  Find Allocator which created the passed argument. Not reentrant.
		 * @param  object [in] object to be evaluated (downcasted to IReflection interface)
		 * @return pointer to ObjectAllocator instance
		 * @see    ObjectFactory::createTypeOf()
		 * @see    ObjectAllocator::createTypeOf()
		 */
		static ObjectAllocator* findAllocatorOf_( IReflection* object );
		/**
		 * @brief  Find first Allocator which matches (supports) the query. Not reentrant.
		 * @param  className [in] full class name of the object (including namespace), may be an abstract interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @param  allocable [in] when true, it will filter results for non-abstract object only
		 * @return pointer to ObjectAllocator instance
		 * @see    ObjectAllocator::isSupported()
		 */
		static ObjectAllocator* findAllocatorOf_( const std::string& className, double version_pattern = 0.0, bool allocable = true );
//@}
	private:
		Response* mmDoRemoveAllocator( const Request* request );
		Response* mmDoSupportsType( const Request* request );
		Response* mmDoFindAllocator( const Request* request );
		Response* mmDoGetTypesTree( const Request* request );

		WRESULT mmDoDump();


}; // class def



 
class StaticAllocator : public ObjectAllocator
 {
	WOSH_CLASSNAME(wosh::StaticAllocator)

	public:
		static StaticAllocator& getInstance(); // meyer singleton

	private:
		StaticAllocator()
			: ObjectAllocator() {
			Object::setName("StaticAllocator");
			Log.setContext( "StaticAllocator", true );
		 }
		StaticAllocator( const StaticAllocator& ) : ObjectAllocator() { }
		StaticAllocator& operator=( const StaticAllocator&  ) { return *this; }

}; // class def

extern StaticAllocator BuiltInAllocator;



}; // namespace wosh

#endif //__WOSH_Core_ObjectFactory_H__
